package com.briup.Server.Store.Impl;

import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.briup.Config.BeanAware;
import com.briup.Config.Impl.SmartConfigImpl;
import com.briup.Config.PropertiesAware;
import com.briup.Config.SmartConfig;
import com.briup.Logger.Impl.LogImpl;
import com.briup.Logger.Log;
import com.briup.Server.Store.DBStore;
import com.briup.Utils.DataUtil;
import com.briup.Utils.PropertiesUtil;
import com.briup.backUp.Backup;
import com.briup.backUp.Impl.BackupImpl;
import com.briup.entity.Environment;
import org.apache.log4j.Logger;

import javax.sql.DataSource;
import java.io.File;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Objects;

public class DBStoreImpl implements DBStore , BeanAware, PropertiesAware {
    //private Log log=new LogImpl();
    private Logger log= Logger.getLogger("com.briup.Server.Store.Impl.DBStoreImpl");

    //备份文件路径
    private String dbstoreBackupFilePath;

    //备份模块对象
    private Backup backup;

//    //加载备份文件D:\training2\idea_code\Smart\src\main\resources\store.backup
//    private File backupPath=new File("D:\\training2\\idea_code\\Smart\\src\\main\\resources\\store.backup");
//    //备份模块对象
//    private Backup backup=new BackupImpl();

    @Override
    public void saveDBStore(Collection<Environment> environments) {
        /**
         * 遍历集合,insert into e_detail_1 (name,srcId,desId,devId,sensorAddress,count,cmd,status,data,gather_date)
         * values (?,?,?,?,?,?,?,?,?,?)
         */
        //备份文件
        File backupPath = new File(dbstoreBackupFilePath);

        //文件不存在会自动创建
        //文件对象.getAbsolutePath()de'd得到绝对路径 false：不删除
        Object object = backup.load(backupPath.getAbsolutePath(), true);

        //判断拿到的对象是否为空
        if (Objects.nonNull(object)) {
            //对象不为空 拿到备份文件中的数据，即未入库的数据
            //类型转换 Object->Collection(存放的是Environment类型数据)
            Collection<Environment> collection = (Collection<Environment>) object;
            //整合  list1.addAll(list2)
            //collection.addAll(environments);
            environments.addAll(collection);
        }

        //声明数据库连接对象
        Connection connection = null;
        //获取数据库操作对象
        PreparedStatement preparedStatement = null;
        //记录上一条环境数据的日期
        int preDay = -1;
        //记录相同日期的数据个数
        int sameCount = 0;
        //统计入库总数量
        int sum = 0;
        try {
            //获取数据源
            DataSource dataSource = DruidDataSourceFactory.createDataSource(PropertiesUtil.getProperties());
            //获取连接对象
            connection = dataSource.getConnection();
            //设置手动提交
            connection.setAutoCommit(false);
            //计数器（遍历多少次）
            int count = 1;
            //遍历集合，存储每一个数据
            for (Environment environment : environments) {
                //获取Environment对象采集的日期
                int currentDay = DataUtil.getDayByTimestamp(environment.getGather_date());
                if (preDay != currentDay) {
                    if (preDay != -1) {
                        //上一次记录的时间与本次遍历的环境数据日期不一致 且不是第一次进入循环
                        //先提交事务再更新，然后重新赋值
                        //批量执行
                        preparedStatement.executeBatch();
                        //提交事务
                        connection.commit();
                        //统计采集数据的数量
                        sum += sameCount;
                        //数据已经提交，相同日期的数量重新置0
                        sameCount = 0;
                        //关闭上一个PS对象
                        preparedStatement.close();
                    }
                    //第一次进入循环preDay==-1，与本次遍历的采集时间肯定不一致
                    String sql = "insert into e_detail_" + currentDay + "(name,srcId,desId,devId,sensorAddress,count,cmd,status,data,gather_date) " +
                            "values (?,?,?,?,?,?,?,?,?,?)";
                    //为ps赋值
                    preparedStatement = connection.prepareStatement(sql);
                    log.warn("即将向e_detail_" + currentDay + "数据库输出数据！");
                }

//                //手动添加异常
//                if (count == 14){
//                    int a = 1 / 0;
//                }

                //为environment对象其他属性赋值
                initPs(environment, preparedStatement);
                //统计自增 相同日期的数据数量自增
                sameCount++;

                //每3条作为一个批次
                if (sameCount % 3 == 0) {
                    //批量执行
                    preparedStatement.executeBatch();
                    connection.commit();
                    //入库总条数
                    sum += sameCount;
                    //sameCount重置
                    sameCount = 0;
                }
                //将当前日期赋给preDay
                preDay = currentDay;
                count++;
            }
            //记录总条数
            sum = sum + sameCount;
            //最后一条数据若和前一条数据日期相同，只会走最后的if()语句，跳出循环，此时这个任务就没有提交
            //批量执行
            preparedStatement.executeBatch();
            //提交事务
            connection.commit();
            log.info("本次共入库" + sum + "条环境数据！");
        } catch (Exception e) {
            try {
                //事务回滚
                connection.rollback();
                //截取未能入库的子集合
                Collection<Environment> collection = ((ArrayList<Environment>)environments).subList(sum,environments.size());

                //将backupCollection值重新赋值给一个Collection集合
                Collection<Environment> backupCollection = new ArrayList<>();
                backupCollection.addAll(collection);

                //未能入库的数据存储在备份文件  false不追加
                backup.save(backupPath.getAbsolutePath(), false, backupCollection);
                log.info("未入库的数据【" + sum + "," + environments.size() + "】，已经保存至备份文件中，地址：" + backupPath.getAbsolutePath());

            } catch (SQLException ex) {
                log.error(ex.getMessage());
            } finally {
                try {
                    if (preparedStatement != null) {
                        preparedStatement.close();
                    }
                    if (connection != null) {
                        connection.close();
                    }
                } catch (Exception ex) {
                    log.error("资源关闭失败...");
                }
            }
        }
    }
    private void initPs(Environment environment ,PreparedStatement preparedStatement) throws SQLException {
        //为10个参数赋值
        preparedStatement.setString(1, environment.getName());
        preparedStatement.setString(2, environment.getSrcId());
        preparedStatement.setString(3, environment.getDesId());
        preparedStatement.setString(4, environment.getDevId());
        preparedStatement.setString(5, environment.getSensorAddress());
        preparedStatement.setInt(6, environment.getCount());
        preparedStatement.setString(7, environment.getCmd());
        preparedStatement.setInt(8, environment.getStatus());
        preparedStatement.setFloat(9,environment.getData());
        preparedStatement.setTimestamp(10,environment.getGather_date());
        //批处理
        preparedStatement.addBatch();
        //只是通过这个方法获取了environment对象的其他属性，没有确定具体的sql语句，不能执行并提交

    }

    @Override
    public void setBean(SmartConfig smartConfig) {
        backup = smartConfig.getBackup();
    }

    @Override
    public void setProperties() {
        dbstoreBackupFilePath = (String) SmartConfigImpl.getPropertiesMap().get("dbstoreBackupFilePath");
    }
}
